#pragma once

#include <iostream>
#include <cstdlib>
#include <errno.h>
#include <functional>
#include <sys/epoll.h>

#include "Sock.hpp"
#include "Log.hpp"

using namespace std;

class EpollServer
{
public:
    static const int gsize = 128;
    static const int num = 256;
    using func_t = function<int(int)>;
public:
//int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
//int epoll_create(int size);
//int  epoll_ctl(int  epfd,  int  op,  int  fd,  struct  epoll_event *event);
    EpollServer(uint16_t port, func_t func):port_(port),listensock_(-1),epfd_(-1),func_(func)
    {

    }

    void InitEpollServer()
    {
        listensock_ = sock::Socket();
        sock::Bind(listensock_, port_);
        sock::Listen(listensock_);

        // 这里直接使用原生接口
        epfd_ = epoll_create(gsize);
        if(epfd_ < 0)
        {
            logMessage(FATAL,"%d:%s", errno, strerror(errno));
            exit(FATAL);
        } 

        logMessage(DEBUG, "创建监听套接字成功: %d", listensock_);
        logMessage(DEBUG, "创建epoll成功: %d", epfd_);
    }

    void HandlerEvents(struct epoll_event revs[], int n)
    {
        for(int i = 0; i < n; ++i)
        {
            int sock = revs[i].data.fd;
            uint32_t revent = revs[i].events;
            if(revent & EPOLLIN)
            {
                if(sock == listensock_)
                {
                    string clientip;
                    uint16_t clientport = 0;
                    // 监听socket就绪， 获取新连接
                    int sockfd = sock::Accept(listensock_, &clientip, &clientport);
                    if(sockfd < 0)
                    {
                        logMessage(FATAL, "%d : %s", errno, strerror(errno));
                        continue;
                    }

                    // 托管epoll
                    struct epoll_event ev;
                    ev.events = EPOLLIN;
                    ev.data.fd = sockfd;

                    int j = epoll_ctl(epfd_, EPOLL_CTL_ADD, sockfd, &ev);
                    assert(j == 0);
                    (void)j;
                }
                else
                {
                    // 普通socket就绪， 进行数据INPUT
                    int j = func_(sock);
                    if(j <= 0)
                    {
                        // 先移除， 再关闭
                        int x = epoll_ctl(epfd_, EPOLL_CTL_DEL, sock, nullptr);
                        assert(x == 0);
                        (void)x;
                        logMessage(DEBUG, "client quit: %d", sock);
                        close(sock);
                    }
                }
            }
        }
    }

    void Run()
    {
        // 1. 先添加listensock_
        struct epoll_event ev;
        ev.events = EPOLLIN;
        ev.data.fd = listensock_;
        int n = epoll_ctl(epfd_, EPOLL_CTL_ADD, listensock_, &ev);
        assert(n == 0);
        (void)n;

        struct epoll_event revs[num];
        int timeout = 1000;
        while(true)
        {
            // 关于n：就绪的fd的个数，只需要进行将底层的就绪队列中的节点，依次从0下标放入revs中即可！
            int n = epoll_wait(epfd_, revs, num, timeout);
            switch(n)
            {
            case 0:
                cout << "time out : " << (unsigned long)time(nullptr) <<endl;
                break;
            case -1:
                cerr << errno << " : " << strerror(errno) << endl;
                break;
            default:
                HandlerEvents(revs, n);
                break;
            }
        }

    }

    ~EpollServer()
    {
        if(epfd_ != -1)
        {
            close(epfd_);
        }

        if(listensock_ != -1)
        {
            close(listensock_);
        }
    }

    private:
        int listensock_;
        int epfd_;
        uint16_t port_;
        func_t func_;

};